/***************************************************************************
draw.c  -  description
-------------------
begin                : Sun Oct 28 2001
copyright            : (C) 2001 by Pete Bernert
email                : BlackDove@addcom.de
***************************************************************************/
/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version. See also the license.txt file for *
*   additional informations.                                              *
*                                                                         *
***************************************************************************/

#define _IN_DRAW

#include "externals.h"
#include "gpu.h"
#include "draw.h"
#include "prim.h"
#include "menu.h"
#include "interp.h"
#include "swap.h"
#include <xtl.h>
#include "xb_video.h"

// misc globals
int            iResX;
int            iResY;
long           lLowerpart;
BOOL           bIsFirstFrame = TRUE;
BOOL           bCheckMask = FALSE;
unsigned short sSetMask = 0;
unsigned long  lSetMask = 0;
int            iDesktopCol = 16;
int            iShowFPS = 0;
int            iWinSize;
int            iMaintainAspect = 0;
int            iUseNoStretchBlt = 0;
int            iFastFwd = 0;
int            iDebugMode = 0;
int            iFVDisplay = 0;
PSXPoint_t     ptCursorPoint[8];
unsigned short usCursorActive = 0;

//unsigned int   LUT16to32[65536];
//unsigned int   RGBtoYUV[65536];


unsigned char *pBackBuffer = 0;
unsigned char *pPsxScreen = 0;

int finalw,finalh;

#include <time.h>

// prototypes
void hq2x_32( unsigned char * srcPtr, DWORD srcPitch, unsigned char * dstPtr, int width, int height);
void hq3x_32( unsigned char * srcPtr,  DWORD srcPitch, unsigned char * dstPtr, int width, int height);
void (*p2XSaIFunc) (unsigned char *, DWORD, unsigned char *, int, int);


////////////////////////////////////////////////////////////////////////
// generic 2xSaI helpers
////////////////////////////////////////////////////////////////////////
void *         pSaISmallBuff=NULL;
void *         pSaIBigBuff=NULL;

#define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D))

static __inline int GetResult1(DWORD A, DWORD B, DWORD C, DWORD D, DWORD E)
{
	int x = 0;
	int y = 0;
	int r = 0;
	if (A == C) x+=1; else if (B == C) y+=1;
	if (A == D) x+=1; else if (B == D) y+=1;
	if (x <= 1) r+=1;
	if (y <= 1) r-=1;
	return r;
}

static __inline int GetResult2(DWORD A, DWORD B, DWORD C, DWORD D, DWORD E)
{
	int x = 0;
	int y = 0;
	int r = 0;
	if (A == C) x+=1; else if (B == C) y+=1;
	if (A == D) x+=1; else if (B == D) y+=1;
	if (x <= 1) r-=1;
	if (y <= 1) r+=1;
	return r;
}

/* Convert RGB to YUV */
__inline uint32_t rgb_to_yuv(uint8_t R, uint8_t G, uint8_t B) {
	uint8_t Y = min(abs(R * 2104 + G * 4130 + B * 802 + 4096 + 131072) >> 13, 235);
	uint8_t U = min(abs(R * -1214 + G * -2384 + B * 3598 + 4096 + 1048576) >> 13, 240);
	uint8_t V = min(abs(R * 3598 + G * -3013 + B * -585 + 4096 + 1048576) >> 13, 240);

#ifdef __BIG_ENDIAN__
	return Y << 24 | U << 16 | Y << 8 | V;
#else
	return Y << 24 | V << 16 | Y << 8 | U;
#endif
}

#define colorMask8     0x00FEFEFE
#define lowPixelMask8  0x00010101
#define qcolorMask8    0x00FCFCFC
#define qlowpixelMask8 0x00030303

#define INTERPOLATE8(A, B) ((((A & colorMask8) >> 1) + ((B & colorMask8) >> 1) + (A & B & lowPixelMask8)))
#define Q_INTERPOLATE8(A, B, C, D) (((((A & qcolorMask8) >> 2) + ((B & qcolorMask8) >> 2) + ((C & qcolorMask8) >> 2) + ((D & qcolorMask8) >> 2) \
	+ ((((A & qlowpixelMask8) + (B & qlowpixelMask8) + (C & qlowpixelMask8) + (D & qlowpixelMask8)) >> 2) & qlowpixelMask8))))


void Super2xSaI_ex8(unsigned char *srcPtr, DWORD srcPitch,
					unsigned char  *dstBitmap, int width, int height)
{
	DWORD dstPitch        = srcPitch<<1;
	DWORD srcPitchHalf    = srcPitch>>1;
	int   finWidth        = srcPitch>>2;
	DWORD line;
	DWORD *dP;
	DWORD *bP;
	int iXA,iXB,iXC,iYA,iYB,iYC,finish;
	DWORD color4, color5, color6;
	DWORD color1, color2, color3;
	DWORD colorA0, colorA1, colorA2, colorA3,
		colorB0, colorB1, colorB2, colorB3,
		colorS1, colorS2;
	DWORD product1a, product1b,
		product2a, product2b;

	finalw=width<<1;
	finalh=height<<1;

	line = 0;

	{
		for (; height; height-=1)
		{
			bP = (DWORD *)srcPtr;
			dP = (DWORD *)(dstBitmap + line*dstPitch);
			for (finish = width; finish; finish -= 1 )
			{
				//---------------------------------------    B1 B2
				//                                         4  5  6 S2
				//                                         1  2  3 S1
				//                                           A1 A2
				if(finish==finWidth) iXA=0;
				else                 iXA=1;
				if(finish>4) {iXB=1;iXC=2;}
				else
					if(finish>3) {iXB=1;iXC=1;}
					else         {iXB=0;iXC=0;}
					if(line==0)  {iYA=0;}
					else         {iYA=finWidth;}
					if(height>4) {iYB=finWidth;iYC=srcPitchHalf;}
					else
						if(height>3) {iYB=finWidth;iYC=finWidth;}
						else         {iYB=0;iYC=0;}

						colorB0 = *(bP- iYA - iXA);
						colorB1 = *(bP- iYA);
						colorB2 = *(bP- iYA + iXB);
						colorB3 = *(bP- iYA + iXC);

						color4 = *(bP  - iXA);
						color5 = *(bP);
						color6 = *(bP  + iXB);
						colorS2 = *(bP + iXC);

						color1 = *(bP  + iYB  - iXA);
						color2 = *(bP  + iYB);
						color3 = *(bP  + iYB  + iXB);
						colorS1= *(bP  + iYB  + iXC);

						colorA0 = *(bP + iYC - iXA);
						colorA1 = *(bP + iYC);
						colorA2 = *(bP + iYC + iXB);
						colorA3 = *(bP + iYC + iXC);

						if (color2 == color6 && color5 != color3)
						{
							product2b = product1b = color2;
						}
						else
							if (color5 == color3 && color2 != color6)
							{
								product2b = product1b = color5;
							}
							else
								if (color5 == color3 && color2 == color6)
								{
									register int r = 0;

									r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (color1&0x00ffffff),  (colorA1&0x00ffffff));
									r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (color4&0x00ffffff),  (colorB1&0x00ffffff));
									r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (colorA2&0x00ffffff), (colorS1&0x00ffffff));
									r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (colorB2&0x00ffffff), (colorS2&0x00ffffff));

									if (r > 0)
										product2b = product1b = color6;
									else
										if (r < 0)
											product2b = product1b = color5;
										else
										{
											product2b = product1b = INTERPOLATE8(color5, color6);
										}
								}
								else
								{
									if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0)
										product2b = Q_INTERPOLATE8 (color3, color3, color3, color2);
									else
										if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3)
											product2b = Q_INTERPOLATE8 (color2, color2, color2, color3);
										else
											product2b = INTERPOLATE8 (color2, color3);

									if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0)
										product1b = Q_INTERPOLATE8 (color6, color6, color6, color5);
									else
										if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3)
											product1b = Q_INTERPOLATE8 (color6, color5, color5, color5);
										else
											product1b = INTERPOLATE8 (color5, color6);
								}

								if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2)
									product2a = INTERPOLATE8(color2, color5);
								else
									if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0)
										product2a = INTERPOLATE8(color2, color5);
									else
										product2a = color2;

								if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2)
									product1a = INTERPOLATE8(color2, color5);
								else
									if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0)
										product1a = INTERPOLATE8(color2, color5);
									else
										product1a = color5;

								*dP=product1a;
								*(dP+1)=product1b;
								*(dP+(srcPitchHalf))=product2a;
								*(dP+1+(srcPitchHalf))=product2b;

								bP += 1;
								dP += 2;
			}//end of for ( finish= width etc..)

			line += 2;
			srcPtr += srcPitch;
		}; //endof: for (; height; height--)
	}
}

////////////////////////////////////////////////////////////////////////

void Std2xSaI_ex8(unsigned char *srcPtr, DWORD srcPitch,
				  unsigned char *dstBitmap, int width, int height)
{
	DWORD dstPitch        = srcPitch<<1;
	DWORD srcPitchHalf    = srcPitch>>1;
	int   finWidth        = srcPitch>>2;
	DWORD line;
	DWORD *dP;
	DWORD *bP;
	int iXA,iXB,iXC,iYA,iYB,iYC,finish;

	DWORD colorA, colorB;
	DWORD colorC, colorD,
		colorE, colorF, colorG, colorH,
		colorI, colorJ, colorK, colorL,
		colorM, colorN, colorO, colorP;
	DWORD product, product1, product2;

	line = 0;

	finalw=width<<1;
	finalh=height<<1;

	{
		for (; height; height-=1)
		{
			bP = (DWORD *)srcPtr;
			dP = (DWORD *)(dstBitmap + line*dstPitch);
			for (finish = width; finish; finish -= 1 )
			{
				//---------------------------------------
				// Map of the pixels:                    I|E F|J
				//                                       G|A B|K
				//                                       H|C D|L
				//                                       M|N O|P
				if(finish==finWidth) iXA=0;
				else                 iXA=1;
				if(finish>4) {iXB=1;iXC=2;}
				else
					if(finish>3) {iXB=1;iXC=1;}
					else         {iXB=0;iXC=0;}
					if(line==0)  {iYA=0;}
					else         {iYA=finWidth;}
					if(height>4) {iYB=finWidth;iYC=srcPitchHalf;}
					else
						if(height>3) {iYB=finWidth;iYC=finWidth;}
						else         {iYB=0;iYC=0;}

						colorI = *(bP- iYA - iXA);
						colorE = *(bP- iYA);
						colorF = *(bP- iYA + iXB);
						colorJ = *(bP- iYA + iXC);

						colorG = *(bP  - iXA);
						colorA = *(bP);
						colorB = *(bP  + iXB);
						colorK = *(bP + iXC);

						colorH = *(bP  + iYB  - iXA);
						colorC = *(bP  + iYB);
						colorD = *(bP  + iYB  + iXB);
						colorL = *(bP  + iYB  + iXC);

						colorM = *(bP + iYC - iXA);
						colorN = *(bP + iYC);
						colorO = *(bP + iYC + iXB);
						colorP = *(bP + iYC + iXC);


						if((colorA == colorD) && (colorB != colorC))
						{
							if(((colorA == colorE) && (colorB == colorL)) ||
								((colorA == colorC) && (colorA == colorF) &&
								(colorB != colorE) && (colorB == colorJ)))
							{
								product = colorA;
							}
							else
							{
								product = INTERPOLATE8(colorA, colorB);
							}

							if(((colorA == colorG) && (colorC == colorO)) ||
								((colorA == colorB) && (colorA == colorH) &&
								(colorG != colorC) && (colorC == colorM)))
							{
								product1 = colorA;
							}
							else
							{
								product1 = INTERPOLATE8(colorA, colorC);
							}
							product2 = colorA;
						}
						else
							if((colorB == colorC) && (colorA != colorD))
							{
								if(((colorB == colorF) && (colorA == colorH)) ||
									((colorB == colorE) && (colorB == colorD) &&
									(colorA != colorF) && (colorA == colorI)))
								{
									product = colorB;
								}
								else
								{
									product = INTERPOLATE8(colorA, colorB);
								}

								if(((colorC == colorH) && (colorA == colorF)) ||
									((colorC == colorG) && (colorC == colorD) &&
									(colorA != colorH) && (colorA == colorI)))
								{
									product1 = colorC;
								}
								else
								{
									product1=INTERPOLATE8(colorA, colorC);
								}
								product2 = colorB;
							}
							else
								if((colorA == colorD) && (colorB == colorC))
								{
									if (colorA == colorB)
									{
										product = colorA;
										product1 = colorA;
										product2 = colorA;
									}
									else
									{
										register int r = 0;
										product1 = INTERPOLATE8(colorA, colorC);
										product = INTERPOLATE8(colorA, colorB);

										r += GetResult1 (colorA&0x00FFFFFF, colorB&0x00FFFFFF, colorG&0x00FFFFFF, colorE&0x00FFFFFF, colorI&0x00FFFFFF);
										r += GetResult2 (colorB&0x00FFFFFF, colorA&0x00FFFFFF, colorK&0x00FFFFFF, colorF&0x00FFFFFF, colorJ&0x00FFFFFF);
										r += GetResult2 (colorB&0x00FFFFFF, colorA&0x00FFFFFF, colorH&0x00FFFFFF, colorN&0x00FFFFFF, colorM&0x00FFFFFF);
										r += GetResult1 (colorA&0x00FFFFFF, colorB&0x00FFFFFF, colorL&0x00FFFFFF, colorO&0x00FFFFFF, colorP&0x00FFFFFF);

										if (r > 0)
											product2 = colorA;
										else
											if (r < 0)
												product2 = colorB;
											else
											{
												product2 = Q_INTERPOLATE8(colorA, colorB, colorC, colorD);
											}
									}
								}
								else
								{
									product2 = Q_INTERPOLATE8(colorA, colorB, colorC, colorD);

									if ((colorA == colorC) && (colorA == colorF) &&
										(colorB != colorE) && (colorB == colorJ))
									{
										product = colorA;
									}
									else
										if ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI))
										{
											product = colorB;
										}
										else
										{
											product = INTERPOLATE8(colorA, colorB);
										}

										if ((colorA == colorB) && (colorA == colorH) &&
											(colorG != colorC) && (colorC == colorM))
										{
											product1 = colorA;
										}
										else
											if ((colorC == colorG) && (colorC == colorD) &&
												(colorA != colorH) && (colorA == colorI))
											{
												product1 = colorC;
											}
											else
											{
												product1 = INTERPOLATE8(colorA, colorC);
											}
								}

								//////////////////////////

								*dP=colorA;
								*(dP+1)=product;
								*(dP+(srcPitchHalf))=product1;
								*(dP+1+(srcPitchHalf))=product2;

								bP += 1;
								dP += 2;
			}//end of for ( finish= width etc..)

			line += 2;
			srcPtr += srcPitch;
		}; //endof: for (; height; height--)
	}
}

////////////////////////////////////////////////////////////////////////

void SuperEagle_ex8(unsigned char *srcPtr, DWORD srcPitch,
					unsigned char  *dstBitmap, int width, int height)
{
	DWORD dstPitch        = srcPitch<<1;
	DWORD srcPitchHalf    = srcPitch>>1;
	int   finWidth        = srcPitch>>2;
	DWORD line;
	DWORD *dP;
	DWORD *bP;
	int iXA,iXB,iXC,iYA,iYB,iYC,finish;
	DWORD color4, color5, color6;
	DWORD color1, color2, color3;
	DWORD colorA1, colorA2,
		colorB1, colorB2,
		colorS1, colorS2;
	DWORD product1a, product1b,
		product2a, product2b;

	finalw=width<<1;
	finalh=height<<1;

	line = 0;

	{
		for (; height; height-=1)
		{
			bP = (DWORD *)srcPtr;
			dP = (DWORD *)(dstBitmap + line*dstPitch);
			for (finish = width; finish; finish -= 1 )
			{
				if(finish==finWidth) iXA=0;
				else                 iXA=1;
				if(finish>4) {iXB=1;iXC=2;}
				else
					if(finish>3) {iXB=1;iXC=1;}
					else         {iXB=0;iXC=0;}
					if(line==0)  {iYA=0;}
					else         {iYA=finWidth;}
					if(height>4) {iYB=finWidth;iYC=srcPitchHalf;}
					else
						if(height>3) {iYB=finWidth;iYC=finWidth;}
						else         {iYB=0;iYC=0;}

						colorB1 = *(bP- iYA);
						colorB2 = *(bP- iYA + iXB);

						color4 = *(bP  - iXA);
						color5 = *(bP);
						color6 = *(bP  + iXB);
						colorS2 = *(bP + iXC);

						color1 = *(bP  + iYB  - iXA);
						color2 = *(bP  + iYB);
						color3 = *(bP  + iYB  + iXB);
						colorS1= *(bP  + iYB  + iXC);

						colorA1 = *(bP + iYC);
						colorA2 = *(bP + iYC + iXB);

						if(color2 == color6 && color5 != color3)
						{
							product1b = product2a = color2;
							if((color1 == color2) ||
								(color6 == colorB2))
							{
								product1a = INTERPOLATE8(color2, color5);
								product1a = INTERPOLATE8(color2, product1a);
							}
							else
							{
								product1a = INTERPOLATE8(color5, color6);
							}

							if((color6 == colorS2) ||
								(color2 == colorA1))
							{
								product2b = INTERPOLATE8(color2, color3);
								product2b = INTERPOLATE8(color2, product2b);
							}
							else
							{
								product2b = INTERPOLATE8(color2, color3);
							}
						}
						else
							if (color5 == color3 && color2 != color6)
							{
								product2b = product1a = color5;

								if ((colorB1 == color5) ||
									(color3 == colorS1))
								{
									product1b = INTERPOLATE8(color5, color6);
									product1b = INTERPOLATE8(color5, product1b);
								}
								else
								{
									product1b = INTERPOLATE8(color5, color6);
								}

								if ((color3 == colorA2) ||
									(color4 == color5))
								{
									product2a = INTERPOLATE8(color5, color2);
									product2a = INTERPOLATE8(color5, product2a);
								}
								else
								{
									product2a = INTERPOLATE8(color2, color3);
								}
							}
							else
								if (color5 == color3 && color2 == color6)
								{
									register int r = 0;

									r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (color1&0x00ffffff),  (colorA1&0x00ffffff));
									r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (color4&0x00ffffff),  (colorB1&0x00ffffff));
									r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (colorA2&0x00ffffff), (colorS1&0x00ffffff));
									r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (colorB2&0x00ffffff), (colorS2&0x00ffffff));

									if (r > 0)
									{
										product1b = product2a = color2;
										product1a = product2b = INTERPOLATE8(color5, color6);
									}
									else
										if (r < 0)
										{
											product2b = product1a = color5;
											product1b = product2a = INTERPOLATE8(color5, color6);
										}
										else
										{
											product2b = product1a = color5;
											product1b = product2a = color2;
										}
								}
								else
								{
									product2b = product1a = INTERPOLATE8(color2, color6);
									product2b = Q_INTERPOLATE8(color3, color3, color3, product2b);
									product1a = Q_INTERPOLATE8(color5, color5, color5, product1a);

									product2a = product1b = INTERPOLATE8(color5, color3);
									product2a = Q_INTERPOLATE8(color2, color2, color2, product2a);
									product1b = Q_INTERPOLATE8(color6, color6, color6, product1b);
								}

								////////////////////////////////

								*dP=product1a;
								*(dP+1)=product1b;
								*(dP+(srcPitchHalf))=product2a;
								*(dP+1+(srcPitchHalf))=product2b;

								bP += 1;
								dP += 2;
			}//end of for ( finish= width etc..)

			line += 2;
			srcPtr += srcPitch;
		}; //endof: for (; height; height--)
	}
}

/////////////////////////

//#include <assert.h>

static __inline void scale2x_32_def_whole(uint32_t*  dst0, uint32_t* dst1, const uint32_t* src0, const uint32_t* src1, const uint32_t* src2, unsigned count)
{

	//assert(count >= 2);

	// first pixel
	if (src0[0] != src2[0] && src1[0] != src1[1]) {
		dst0[0] = src1[0] == src0[0] ? src0[0] : src1[0];
		dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0];
		dst1[0] = src1[0] == src2[0] ? src2[0] : src1[0];
		dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0];
	} else {
		dst0[0] = src1[0];
		dst0[1] = src1[0];
		dst1[0] = src1[0];
		dst1[1] = src1[0];
	}
	++src0;
	++src1;
	++src2;
	dst0 += 2;
	dst1 += 2;

	// central pixels
	count -= 2;
	while (count) {
		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
			dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
			dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0];
			dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0];
			dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0];
		} else {
			dst0[0] = src1[0];
			dst0[1] = src1[0];
			dst1[0] = src1[0];
			dst1[1] = src1[0];
		}

		++src0;
		++src1;
		++src2;
		dst0 += 2;
		dst1 += 2;
		--count;
	}

	// last pixel
	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
		dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
		dst0[1] = src1[0] == src0[0] ? src0[0] : src1[0];
		dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0];
		dst1[1] = src1[0] == src2[0] ? src2[0] : src1[0];
	} else {
		dst0[0] = src1[0];
		dst0[1] = src1[0];
		dst1[0] = src1[0];
		dst1[1] = src1[0];
	}
}

void Scale2x_ex8(unsigned char *srcPtr, DWORD srcPitch,
				 unsigned char  *dstPtr, int width, int height)
{
	//const int srcpitch = srcPitch;
	const int dstPitch = srcPitch<<1;

	int count = height;

	uint32_t  *dst0 = (uint32_t  *)dstPtr;
	uint32_t  *dst1 = dst0 + (dstPitch >> 2);

	uint32_t  *src0 = (uint32_t  *)srcPtr;
	uint32_t  *src1 = src0 + (srcPitch >> 2);
	uint32_t  *src2 = src1 + (srcPitch >> 2);

	finalw=width<<1;
	finalh=height<<1;

	scale2x_32_def_whole(dst0, dst1, src0, src0, src1, width);

	count -= 2;
	while(count) {
		dst0 += dstPitch >> 1;
		dst1 += dstPitch >> 1;
		scale2x_32_def_whole(dst0, dst1, src0, src0, src1, width);
		src0 = src1;
		src1 = src2;
		src2 += srcPitch >> 2;
		--count;
	}
	dst0 += dstPitch >> 1;
	dst1 += dstPitch >> 1;
	scale2x_32_def_whole(dst0, dst1, src0, src1, src1, width);

}

////////////////////////////////////////////////////////////////////////

static __inline void scale3x_32_def_whole(uint32_t* dst0, uint32_t* dst1, uint32_t* dst2, const uint32_t* src0, const uint32_t* src1, const uint32_t* src2, unsigned count)
{
	//assert(count >= 2);

	//first pixel
	if (src0[0] != src2[0] && src1[0] != src1[1]) {
		dst0[0] = src1[0];
		dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
		dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
		dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
		dst1[1] = src1[0];
		dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
		dst2[0] = src1[0];
		dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0];
		dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
	} else {
		dst0[0] = src1[0];
		dst0[1] = src1[0];
		dst0[2] = src1[0];
		dst1[0] = src1[0];
		dst1[1] = src1[0];
		dst1[2] = src1[0];
		dst2[0] = src1[0];
		dst2[1] = src1[0];
		dst2[2] = src1[0];
	}
	++src0;
	++src1;
	++src2;
	dst0 += 3;
	dst1 += 3;
	dst2 += 3;

	//central pixels
	count -= 2;
	while (count) {
		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
			dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
			dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
			dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
			dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
			dst1[1] = src1[0];
			dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
			dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
			dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
			dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
		} else {
			dst0[0] = src1[0];
			dst0[1] = src1[0];
			dst0[2] = src1[0];
			dst1[0] = src1[0];
			dst1[1] = src1[0];
			dst1[2] = src1[0];
			dst2[0] = src1[0];
			dst2[1] = src1[0];
			dst2[2] = src1[0];
		}

		++src0;
		++src1;
		++src2;
		dst0 += 3;
		dst1 += 3;
		dst2 += 3;
		--count;
	}

	// last pixel
	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
		dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
		dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
		dst0[2] = src1[0];
		dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
		dst1[1] = src1[0];
		dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
		dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
		dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
		dst2[2] = src1[0];
	} else {
		dst0[0] = src1[0];
		dst0[1] = src1[0];
		dst0[2] = src1[0];
		dst1[0] = src1[0];
		dst1[1] = src1[0];
		dst1[2] = src1[0];
		dst2[0] = src1[0];
		dst2[1] = src1[0];
		dst2[2] = src1[0];
	}
}


void Scale3x_ex8(unsigned char *srcPtr, DWORD srcPitch,
				 unsigned char  *dstPtr, int width, int height)
{
	int count = height;

	int dstPitch = srcPitch*3;
	int dstRowPixels = dstPitch>>2;

	uint32_t  *dst0 = (uint32_t  *)dstPtr;
	uint32_t  *dst1 = dst0 + dstRowPixels;
	uint32_t  *dst2 = dst1 + dstRowPixels;

	uint32_t  *src0 = (uint32_t  *)srcPtr;
	uint32_t  *src1 = src0 + (srcPitch >> 2);
	uint32_t  *src2 = src1 + (srcPitch >> 2);

	finalw=width*3;
	finalh=height*3;

	scale3x_32_def_whole(dst0, dst1, dst2, src0, src0, src2, width);

	count -= 2;
	while(count) {
		dst0 += dstRowPixels*3;
		dst1 += dstRowPixels*3;
		dst2 += dstRowPixels*3;

		scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src2, width);
		src0 = src1;
		src1 = src2;
		src2 += srcPitch >> 2;
		--count;
	}

	dst0 += dstRowPixels*3;
	dst1 += dstRowPixels*3;
	dst2 += dstRowPixels*3;

	scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src1, width);
}


////////////////////////////////////////////////////////////////////////

#ifndef MAX
#define MAX(a,b)    (((a) > (b)) ? (a) : (b))
#define MIN(a,b)    (((a) < (b)) ? (a) : (b))
#endif


////////////////////////////////////////////////////////////////////////
// X STUFF :)
////////////////////////////////////////////////////////////////////////
char *               Xpixels;
char *               pCaptionText;

static int fx=0;

// close display

void DestroyDisplay(void)
{

}

static int depth=0;
int root_window_id=0;


// Create display
void CreateDisplay(void){

};


#define vecLoad(v, val) {v.u[0]=val;v.u[1]=val;v.u[2]=val;v.u[3]=val;}

void BlitScreen32(unsigned char * surf, int32_t x, int32_t y)
{
	uint16_t * psxVr16 = psxVuw;
	uint32_t * destpix;
	unsigned char *pD;
	unsigned int startxy;
	uint32_t lu;
	
	unsigned short s, s1, s2, s3, s4, s5, s6, s7;
	uint32_t d, d1, d2, d3, d4, d5, d6, d7;
	unsigned short row, column;
	unsigned short dx = PreviousPSXDisplay.Range.x1;
	unsigned short dy = PreviousPSXDisplay.DisplayMode.y;

	int loop = 0;
	int offset = 0;
	int32_t lPitch = PSXDisplay.DisplayMode.x << 2;
	
	/*
	// Prefetch
	for(loop=0; loop < 1024; loop += 128)
		__dcbt(loop, psxVr16);

	__dcbz128(0, surf);
	*/

	// 
	if (PreviousPSXDisplay.Range.y0) // centering needed?
	{
		XMemSet(surf, 0, (PreviousPSXDisplay.Range.y0 >> 1) * lPitch);

		dy -= PreviousPSXDisplay.Range.y0;
		surf += (PreviousPSXDisplay.Range.y0 >> 1) * lPitch;

		XMemSet(surf + dy * lPitch,
			0, ((PreviousPSXDisplay.Range.y0 + 1) >> 1) * lPitch);
	}

	if (PreviousPSXDisplay.Range.x0)
	{
		for (column = 0; column < dy; column++)
		{
			destpix = (uint32_t *)(surf + (column * lPitch));
			XMemSet(destpix, 0, PreviousPSXDisplay.Range.x0 << 2);
		}
		surf += PreviousPSXDisplay.Range.x0 << 2;
	}

	if (PSXDisplay.RGB24)
	{
		for (column = 0; column < dy; column++)
		{
			startxy = ((1024) * (column + y)) + x;
			pD = (unsigned char *)&psxVuw[startxy];
			destpix = (uint32_t *)(surf + (column * lPitch));
			for (row = 0; row < dx; row++)
			{
				
				lu = *((uint32_t *)pD);

				d = 0xff000000 | (RED(lu) << 16) | (GREEN(lu) << 8) | (BLUE(lu));
				
				destpix[row] = d;

				pD += 3;
			}
		}
	}
	else
	{
		for (column = 0;column<dy;column++)
		{
			startxy = (1024 * (column + y)) + x;
			destpix = (uint32_t *)(surf + (column * lPitch));

			for (row = 0; row < dx; row+=8)
			{		
				s =    __loadshortbytereverse(0,&psxVuw[startxy++]);
				s1 =   __loadshortbytereverse(0,&psxVuw[startxy++]);
				s2 =   __loadshortbytereverse(0,&psxVuw[startxy++]);
				s3 =   __loadshortbytereverse(0,&psxVuw[startxy++]);
				s4 =   __loadshortbytereverse(0,&psxVuw[startxy++]);
				s5 =   __loadshortbytereverse(0,&psxVuw[startxy++]);
				s6 =   __loadshortbytereverse(0,&psxVuw[startxy++]);
				s7 =   __loadshortbytereverse(0,&psxVuw[startxy++]);

				/**/
				d =  (((s << 19) & 0xf80000) | ((s << 6) & 0xf800) | ((s >> 7) & 0xf8)) | 0xff000000;
				d1 = (((s1 << 19) & 0xf80000) | ((s1 << 6) & 0xf800) | ((s1 >> 7) & 0xf8)) | 0xff000000;
				d2 = (((s2 << 19) & 0xf80000) | ((s2 << 6) & 0xf800) | ((s2 >> 7) & 0xf8)) | 0xff000000;
				d3 = (((s3 << 19) & 0xf80000) | ((s3 << 6) & 0xf800) | ((s3 >> 7) & 0xf8)) | 0xff000000;
				d4 = (((s4 << 19) & 0xf80000) | ((s4 << 6) & 0xf800) | ((s4 >> 7) & 0xf8)) | 0xff000000;
				d5 = (((s5 << 19) & 0xf80000) | ((s5 << 6) & 0xf800) | ((s5 >> 7) & 0xf8)) | 0xff000000;
				d6 = (((s6 << 19) & 0xf80000) | ((s6 << 6) & 0xf800) | ((s6 >> 7) & 0xf8)) | 0xff000000;
				d7 = (((s7 << 19) & 0xf80000) | ((s7 << 6) & 0xf800) | ((s7 >> 7) & 0xf8)) | 0xff000000; 

				destpix[row] = d;
				destpix[row+1] = d1;
				destpix[row+2] = d2;
				destpix[row+3] = d3;
				destpix[row+4] = d4;
				destpix[row+5] = d5;
				destpix[row+6] = d6;
				destpix[row+7] = d7;
			}
		}
	}
}



void BlitToYUV(unsigned char * surf,int32_t x,int32_t y)
{
	unsigned char * pD;
	unsigned int startxy;
	uint32_t lu;unsigned short s;
	unsigned short row,column;
	unsigned short dx = PreviousPSXDisplay.Range.x1;
	unsigned short dy = PreviousPSXDisplay.DisplayMode.y;
	int R,G,B;

	int32_t lPitch = PSXDisplay.DisplayMode.x << 2;
	uint32_t *destpix;

	if (PreviousPSXDisplay.Range.y0) // centering needed?
	{
		for (column = 0; column < (PreviousPSXDisplay.Range.y0 >> 1); column++)
		{
			destpix = (uint32_t *)(surf + column * lPitch);
			for (row = 0; row < dx; row++)
			{
				destpix[row] = (4 << 24) | (128 << 16) | (4 << 8) | 128;
			}
		}

		dy -= PreviousPSXDisplay.Range.y0;
		surf += (PreviousPSXDisplay.Range.y0 >> 1) * lPitch;

		for (column = 0; column < (PreviousPSXDisplay.Range.y0 + 1) >> 1; column++)
		{
			destpix = (uint32_t *)(surf + (dy + column) * lPitch);
			for (row = 0; row < dx; row++)
			{
				destpix[row] = (4 << 24) | (128 << 16) | (4 << 8) | 128;
			}
		}
	}

	if (PreviousPSXDisplay.Range.x0)
	{
		for (column = 0; column < dy; column++)
		{
			destpix = (uint32_t *)(surf + (column * lPitch));
			for (row = 0; row < PreviousPSXDisplay.Range.x0; row++)
			{
				destpix[row] = (4 << 24) | (128 << 16) | (4 << 8) | 128;
			}
		}
		surf += PreviousPSXDisplay.Range.x0 << 2;
	}

	if (PSXDisplay.RGB24)
	{
		for (column = 0; column < dy; column++)
		{
			startxy = (1024 * (column + y)) + x;
			pD = (unsigned char *)&psxVuw[startxy];
			destpix = (uint32_t *)(surf + (column * lPitch));
			for (row = 0; row < dx; row++)
			{
				lu = *((uint32_t *)pD);

				R = RED(lu);
				G = GREEN(lu);
				B = BLUE(lu);

				destpix[row] = rgb_to_yuv(R, G, B);

				pD += 3;
			}
		}
	}
	else
	{
		for (column = 0; column < dy; column++)
		{
			startxy = (1024 * (column + y)) + x;
			destpix = (uint32_t *)(surf + (column * lPitch));
			for (row = 0; row < dx; row++)
			{
				s = GETLE16(&psxVuw[startxy++]);

				R = (s << 3) &0xf8;
				G = (s >> 2) &0xf8;
				B = (s >> 7) &0xf8;

				destpix[row] = rgb_to_yuv(R, G, B);

			}
		}
	}
}

//dst will have half the pitch (32bit to 16bit)
void RGB2YUV(uint32_t *s, int width, int height, uint32_t *d)
{
	int x,y;
	int R,G,B, Y1,Y2,U,V;

	for (y=0; y<height; y++) {
		for(x=0; x<width>>1; x++) {
			R = (*s >> 16) & 0xff;
			G = (*s >> 8) & 0xff;
			B = *s & 0xff;
			s++;

			Y1 = min(abs(R * 2104 + G * 4130 + B * 802 + 4096 + 131072) >> 13, 235);
			U = min(abs(R * -1214 + G * -2384 + B * 3598 + 4096 + 1048576) >> 13, 240);
			V = min(abs(R * 3598 + G * -3013 + B * -585 + 4096 + 1048576) >> 13, 240);

			R = (*s >> 16) & 0xff;
			G = (*s >> 8) & 0xff;
			B = *s & 0xff;
			s++;

			Y2 = min(abs(R * 2104 + G * 4130 + B * 802 + 4096 + 131072) >> 13, 235);

#ifdef __BIG_ENDIAN__
			*d = V | Y2 << 8 | U << 16 | Y1 << 24;
#else
			*d = U | Y1 << 8 | V << 16 | Y2 << 24;
#endif
			d++;
		}
	}
}

extern time_t tStart;

/* compute the position and the size of output screen
* The aspect of the psx output mode is preserved.
* Note: dest dx,dy,dw,dh are both input and output variables
*/
__inline void MaintainAspect(uint32_t * dx, uint32_t * dy, uint32_t * dw, uint32_t * dh)
{
}

unsigned char * pPsxScreenThread;

/*
int InitThread(){
	pPsxScreenThread = (unsigned char *)malloc(1024*1024*4); //4mo

	hSwapThread = CreateThread( 
        NULL,                   // default security attributes
        0,                      // use default stack size  
        SwapThread,      // thread function name
		NULL,					// argument to thread function 
        CREATE_SUSPENDED,       // use default creation flags 
        &g_dwId
	);   // returns the thread identifier 

	XSetThreadProcessor(hSwapThread,2);
	SetThreadPriority(hSwapThread,THREAD_PRIORITY_HIGHEST);
	ResumeThread(hDmaThread);
}
*/


typedef struct __bsw{
	PSXDisplay_t PSXDisplay;
	PSXDisplay_t PreviousPSXDisplay;
	unsigned short * psxuvw;
} ParamUpdateDisplay;


void DoBufferSwap(void)
{
	finalw = PSXDisplay.DisplayMode.x;
	finalh = PSXDisplay.DisplayMode.y;

	UpdateScrenRes(PSXDisplay.DisplayMode.x,PSXDisplay.DisplayMode.y);

	//A faire dans un thread
	BlitScreen32((unsigned char *)pPsxScreen, PSXDisplay.DisplayPosition.x, PSXDisplay.DisplayPosition.y);

	XbDispUpdate();

	UnlockLockDisplay();
}

void DoClearScreenBuffer(void)                         // CLEAR DX BUFFER
{
}

void DoClearFrontBuffer(void)                          // CLEAR DX BUFFER
{/*
 XPutImage(display,window,hGC, XCimage,
 0, 0, 0, 0, iResX, iResY);
 XSync(display,False);*/
}

int Xinitialize()
{
	VideoInit();

	iDesktopCol=32;

	p2XSaIFunc=Std2xSaI_ex8;

	if(iUseNoStretchBlt>0)
	{
		// pBackBuffer=(unsigned char *)malloc(640*512*sizeof(uint32_t));
		pBackBuffer = (unsigned char *)XPhysicalAlloc(
			640*512*sizeof(uint32_t),MAXULONG_PTR, 
			0,PAGE_READWRITE | MEM_LARGE_PAGES
		);
		memset(pBackBuffer,0,640*512*sizeof(uint32_t));
	}

	// pSaIBigBuff=malloc(640*512*4*3*3);
	pSaIBigBuff = (void *)XPhysicalAlloc(
		640*512*4*3*3,MAXULONG_PTR, 
		0,PAGE_READWRITE | MEM_LARGE_PAGES
	);

    memset(pSaIBigBuff,0,640*512*4*3*3);

/*
	pPsxScreen=(unsigned char *)malloc(640*512*sizeof(uint32_t));
	memset(pPsxScreen,0,640*512*sizeof(uint32_t));
*/
	p2XSaIFunc=Std2xSaI_ex8;

	if(iUseNoStretchBlt==1)
	{
		p2XSaIFunc=Std2xSaI_ex8;
	}

	if(iUseNoStretchBlt==2)
	{
		p2XSaIFunc=Super2xSaI_ex8;
	}

	if(iUseNoStretchBlt==3)
	{
		p2XSaIFunc=SuperEagle_ex8;
	}

	if(iUseNoStretchBlt==4)
	{
		p2XSaIFunc=Scale2x_ex8;
	}
	if(iUseNoStretchBlt==5)
	{
		p2XSaIFunc=Scale3x_ex8;
	}
	if(iUseNoStretchBlt==6)
	{
		p2XSaIFunc=hq2x_32;
	}
	if(iUseNoStretchBlt==7)
	{
		p2XSaIFunc=hq3x_32;
	}

	bUsingTWin=FALSE;

	InitMenu();

	bIsFirstFrame = FALSE;                                // done

	if(iShowFPS)
	{
		iShowFPS=0;
		ulKeybits|=KEY_SHOWFPS;
		szDispBuf[0]=0;
		BuildDispMenu(0);
	}

	return 0;
}

void Xcleanup()                                        // X CLEANUP
{
	CloseMenu();

	if(iUseNoStretchBlt>0)
	{
		if(pBackBuffer)  free(pBackBuffer);
		pBackBuffer=0;
		if(pSaIBigBuff) free(pSaIBigBuff);
		pSaIBigBuff=0;
	}
}

unsigned long ulInitDisplay(void)
{
	CreateDisplay();                                      // x stuff
	Xinitialize();                                        // init x
	return 1;
}

void CloseDisplay(void)
{
	Xcleanup();                                           // cleanup dx
	DestroyDisplay();
}

void CreatePic(unsigned char * pMem)
{
}

void DestroyPic(void)
{
}

void DisplayPic(void)
{
}

void ShowGpuPic(void)
{
}

void ShowTextGpuPic(void)
{
}

static void hq2x_32_def(uint32_t * dst0, uint32_t * dst1, const uint32_t * src0, const uint32_t * src1, const uint32_t * src2, unsigned count)
{
	static unsigned char cache_vert_mask[640];
	unsigned char cache_horiz_mask = 0;

	unsigned i;
	unsigned char mask;
	uint32_t  c[9];

	if (src0 == src1)	//processing first row
		memset(cache_vert_mask, 0, count);

	for(i=0;i<count;++i) {
		c[1] = src0[0];
		c[4] = src1[0];
		c[7] = src2[0];

		if (i>0) {
			c[0] = src0[-1];
			c[3] = src1[-1];
			c[6] = src2[-1];
		} else {
			c[0] = c[1];
			c[3] = c[4];
			c[6] = c[7];
		}

		if (i<count-1) {
			c[2] = src0[1];
			c[5] = src1[1];
			c[8] = src2[1];
		} else {
			c[2] = c[1];
			c[5] = c[4];
			c[8] = c[7];
		}

		mask = 0;

		mask |= interp_32_diff(c[0], c[4]) << 0;
		mask |= cache_vert_mask[i];
		mask |= interp_32_diff(c[2], c[4]) << 2;
		mask |= cache_horiz_mask;
		cache_horiz_mask = interp_32_diff(c[5], c[4]) << 3;
		mask |= cache_horiz_mask << 1;	// << 3 << 1 == << 4
		mask |= interp_32_diff(c[6], c[4]) << 5;
		cache_vert_mask[i] = interp_32_diff(c[7], c[4]) << 1;
		mask |= cache_vert_mask[i] << 5; // << 1 << 5 == << 6
		mask |= interp_32_diff(c[8], c[4]) << 7;

#define P0 dst0[0]
#define P1 dst0[1]
#define P2 dst1[0]
#define P3 dst1[1]
#define MUR interp_32_diff(c[1], c[5])
#define MDR interp_32_diff(c[5], c[7])
#define MDL interp_32_diff(c[7], c[3])
#define MUL interp_32_diff(c[3], c[1])
#define IC(p0) c[p0]
#define I11(p0,p1) interp_32_11(c[p0], c[p1])
#define I211(p0,p1,p2) interp_32_211(c[p0], c[p1], c[p2])
#define I31(p0,p1) interp_32_31(c[p0], c[p1])
#define I332(p0,p1,p2) interp_32_332(c[p0], c[p1], c[p2])
#define I431(p0,p1,p2) interp_32_431(c[p0], c[p1], c[p2])
#define I521(p0,p1,p2) interp_32_521(c[p0], c[p1], c[p2])
#define I53(p0,p1) interp_32_53(c[p0], c[p1])
#define I611(p0,p1,p2) interp_32_611(c[p0], c[p1], c[p2])
#define I71(p0,p1) interp_32_71(c[p0], c[p1])
#define I772(p0,p1,p2) interp_32_772(c[p0], c[p1], c[p2])
#define I97(p0,p1) interp_32_97(c[p0], c[p1])
#define I1411(p0,p1,p2) interp_32_1411(c[p0], c[p1], c[p2])
#define I151(p0,p1) interp_32_151(c[p0], c[p1])

		switch (mask) {
#include "hq2x.h"
		}

#undef P0
#undef P1
#undef P2
#undef P3
#undef MUR
#undef MDR
#undef MDL
#undef MUL
#undef IC
#undef I11
#undef I211
#undef I31
#undef I332
#undef I431
#undef I521
#undef I53
#undef I611
#undef I71
#undef I772
#undef I97
#undef I1411
#undef I151

		src0 += 1;
		src1 += 1;
		src2 += 1;
		dst0 += 2;
		dst1 += 2;
	}
}

void hq2x_32( unsigned char * srcPtr,  DWORD srcPitch, unsigned char * dstPtr, int width, int height)
{
	const int dstPitch = srcPitch<<1;

	int count = height;

	uint32_t  *dst0 = (uint32_t  *)dstPtr;
	uint32_t  *dst1 = dst0 + (dstPitch >> 2);

	uint32_t  *src0 = (uint32_t  *)srcPtr;
	uint32_t  *src1 = src0 + (srcPitch >> 2);
	uint32_t  *src2 = src1 + (srcPitch >> 2);

	finalw=width*2;
	finalh=height*2;

	hq2x_32_def(dst0, dst1, src0, src0, src1, width);


	count -= 2;
	while(count) {
		dst0 += dstPitch >> 1;		//next 2 lines (dstPitch / 4 char per int * 2)
		dst1 += dstPitch >> 1;
		hq2x_32_def(dst0, dst1, src0, src1, src2, width);
		src0 = src1;
		src1 = src2;
		src2 += srcPitch >> 2;
		--count;
	}
	dst0 += dstPitch >> 1;
	dst1 += dstPitch >> 1;
	hq2x_32_def(dst0, dst1, src0, src1, src1, width);
}

static void hq3x_32_def(uint32_t*  dst0, uint32_t*  dst1, uint32_t*  dst2, const uint32_t* src0, const uint32_t* src1, const uint32_t* src2, unsigned count)
{
	static unsigned char cache_vert_mask[640];
	unsigned char cache_horiz_mask = 0;

	unsigned i;
	unsigned char mask;
	uint32_t  c[9];

	if (src0 == src1)	//processing first row
		memset(cache_vert_mask, 0, count);

	for(i=0;i<count;++i) {
		c[1] = src0[0];
		c[4] = src1[0];
		c[7] = src2[0];

		if (i>0) {
			c[0] = src0[-1];
			c[3] = src1[-1];
			c[6] = src2[-1];
		} else {
			c[0] = c[1];
			c[3] = c[4];
			c[6] = c[7];
		}

		if (i<count-1) {
			c[2] = src0[1];
			c[5] = src1[1];
			c[8] = src2[1];
		} else {
			c[2] = c[1];
			c[5] = c[4];
			c[8] = c[7];
		}

		mask = 0;

		mask |= interp_32_diff(c[0], c[4]) << 0;
		mask |= cache_vert_mask[i];
		mask |= interp_32_diff(c[2], c[4]) << 2;
		mask |= cache_horiz_mask;
		cache_horiz_mask = interp_32_diff(c[5], c[4]) << 3;
		mask |= cache_horiz_mask << 1;	// << 3 << 1 == << 4
		mask |= interp_32_diff(c[6], c[4]) << 5;
		cache_vert_mask[i] = interp_32_diff(c[7], c[4]) << 1;
		mask |= cache_vert_mask[i] << 5; // << 1 << 5 == << 6
		mask |= interp_32_diff(c[8], c[4]) << 7;

#define P0 dst0[0]
#define P1 dst0[1]
#define P2 dst0[2]
#define P3 dst1[0]
#define P4 dst1[1]
#define P5 dst1[2]
#define P6 dst2[0]
#define P7 dst2[1]
#define P8 dst2[2]
#define MUR interp_32_diff(c[1], c[5])
#define MDR interp_32_diff(c[5], c[7])
#define MDL interp_32_diff(c[7], c[3])
#define MUL interp_32_diff(c[3], c[1])
#define IC(p0) c[p0]
#define I11(p0,p1) interp_32_11(c[p0], c[p1])
#define I211(p0,p1,p2) interp_32_211(c[p0], c[p1], c[p2])
#define I31(p0,p1) interp_32_31(c[p0], c[p1])
#define I332(p0,p1,p2) interp_32_332(c[p0], c[p1], c[p2])
#define I431(p0,p1,p2) interp_32_431(c[p0], c[p1], c[p2])
#define I521(p0,p1,p2) interp_32_521(c[p0], c[p1], c[p2])
#define I53(p0,p1) interp_32_53(c[p0], c[p1])
#define I611(p0,p1,p2) interp_32_611(c[p0], c[p1], c[p2])
#define I71(p0,p1) interp_32_71(c[p0], c[p1])
#define I772(p0,p1,p2) interp_32_772(c[p0], c[p1], c[p2])
#define I97(p0,p1) interp_32_97(c[p0], c[p1])
#define I1411(p0,p1,p2) interp_32_1411(c[p0], c[p1], c[p2])
#define I151(p0,p1) interp_32_151(c[p0], c[p1])

		switch (mask) {
#include "hq3x.h"
		}

#undef P0
#undef P1
#undef P2
#undef P3
#undef P4
#undef P5
#undef P6
#undef P7
#undef P8
#undef MUR
#undef MDR
#undef MDL
#undef MUL
#undef IC
#undef I11
#undef I211
#undef I31
#undef I332
#undef I431
#undef I521
#undef I53
#undef I611
#undef I71
#undef I772
#undef I97
#undef I1411
#undef I151

		src0 += 1;
		src1 += 1;
		src2 += 1;
		dst0 += 3;
		dst1 += 3;
		dst2 += 3;
	}
}

void hq3x_32( unsigned char * srcPtr,  DWORD srcPitch, unsigned char * dstPtr, int width, int height)
{
	int count = height;

	int dstPitch = srcPitch*3;
	int dstRowPixels = dstPitch>>2;

	uint32_t  *dst0 = (uint32_t  *)dstPtr;
	uint32_t  *dst1 = dst0 + dstRowPixels;
	uint32_t  *dst2 = dst1 + dstRowPixels;

	uint32_t  *src0 = (uint32_t  *)srcPtr;
	uint32_t  *src1 = src0 + (srcPitch >> 2);
	uint32_t  *src2 = src1 + (srcPitch >> 2);

	finalw=width*3;
	finalh=height*3;

	hq3x_32_def(dst0, dst1, dst2, src0, src0, src2, width);

	count -= 2;
	while(count) {
		dst0 += dstRowPixels * 3;
		dst1 += dstRowPixels * 3;
		dst2 += dstRowPixels * 3;

		hq3x_32_def(dst0, dst1, dst2, src0, src1, src2, width);
		src0 = src1;
		src1 = src2;
		src2 += srcPitch >> 2;
		--count;
	}
	dst0 += dstRowPixels * 3;
	dst1 += dstRowPixels * 3;
	dst2 += dstRowPixels * 3;

	hq3x_32_def(dst0, dst1, dst2, src0, src1, src1, width);

}
